package com.puff.framework.threadlocal;

public class FastThreadLocal<V> {

	/**
	 * Returns the number of thread local variables bound to the current thread.
	 */
	public static int size() {
		FastThreadLocalMap threadLocalMap = FastThreadLocalMap.getIfSet();
		if (threadLocalMap == null) {
			return 0;
		} else {
			return threadLocalMap.size();
		}
	}

	public static void destroy() {
		FastThreadLocalMap.destroy();
	}

	private final int index;

	public FastThreadLocal() {
		index = FastThreadLocalMap.nextVariableIndex();
	}

	/**
	 * Returns the current value for the current thread
	 */
	@SuppressWarnings("unchecked")
	public final V get() {
		FastThreadLocalMap threadLocalMap = FastThreadLocalMap.get();
		Object v = threadLocalMap.indexedVariable(index);
		if (FastThreadLocalMap.UNSET != v) {
			return (V) v;
		}
		return initialize(threadLocalMap);
	}

	private V initialize(FastThreadLocalMap threadLocalMap) {
		V v = null;
		try {
			v = initialValue();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		threadLocalMap.setIndexedVariable(index, v);
		return v;
	}

	/**
	 * Set the value for the current thread.
	 */
	public final void set(V value) {
		if (value == null || FastThreadLocalMap.UNSET == value) {
			remove();
		} else {
			FastThreadLocalMap threadLocalMap = FastThreadLocalMap.get();
			threadLocalMap.setIndexedVariable(index, value);
		}
	}

	/**
	 * Sets the value to uninitialized; a proceeding call to get() will trigger a call to initialValue().
	 */
	@SuppressWarnings("unchecked")
	public final void remove() {
		FastThreadLocalMap threadLocalMap = FastThreadLocalMap.getIfSet();
		if (threadLocalMap == null) {
			return;
		}
		Object v = threadLocalMap.removeIndexedVariable(index);
		if (FastThreadLocalMap.UNSET != v) {
			try {
				onRemoval((V) v);
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
	}

	/**
	 * Returns the initial value for this thread-local variable.
	 */
	protected V initialValue() throws Exception {
		return null;
	}

	/**
	 * Invoked when this thread local variable is removed by {@link #remove()}.
	 */
	protected void onRemoval(V value) throws Exception {
	}
}
